/*
将一个方法调用和一个方法体关联起来的动作称为绑定。

后期绑定，这意味着绑定发生在运行时，并基于对象的类型。
当一种语言实现后期绑定时，必须有某种机制在运行时来确定对象的类型，并调用恰当的方法。
也就是说，编译器仍然不知道对象的类型，但方法调用机制能找到并调用正确的方法体。
 */

import java.util.Random;

class Shape2D {
    void draw() {
    }

    void erase() {
    }
}

class Circle2D extends Shape2D {
    @Override
    void draw() {
        System.out.println("draw circle");
    }

    @Override
    void erase() {
        System.out.println("erase circle");
    }
}

class Squire2D extends Shape2D {
    @Override
    void draw() {
        System.out.println("draw squire");
    }

    @Override
    void erase() {
        System.out.println("erase squire");
    }
}

class Triangle2D extends Shape2D {
    @Override
    void draw() {
        System.out.println("draw triangle");
    }

    @Override
    void erase() {
        System.out.println("erase triangle");
    }
}

class RandomShapes {
    private Random random = new Random(100);

    public Shape2D getShape() {
        switch (random.nextInt(6)) {
            default:
            case 0:
                return new Circle2D();
            case 1:
                return new Squire2D();
            case 2:
                return new Triangle2D();
        }
    }

    public Shape2D[] array(int size) {
        Shape2D[] shapes = new Shape2D[size];
        for (int i = 0; i < shapes.length; i++) {
            shapes[i] = getShape();
        }
        return shapes;
    }
}

public class ShapeDemo {
    public static void main(String[] args) {
        RandomShapes randomShapes = new RandomShapes();
        Shape2D[] shapes = randomShapes.array(9);
        for (Shape2D shape : shapes) {
            shape.draw();
        }
    }
}
